﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LaughingDog.GameObjects;
using FarseerGames.FarseerPhysics.Dynamics;
using FarseerGames.FarseerPhysics.Factories;
using Microsoft.Xna.Framework;
using FarseerGames.FarseerPhysics.Collisions;

namespace LaughingDog.Components
{
    public class RigidBody : Behaviour
    {        
        protected Body mBody = null;
        protected const Single DEFAULT_MASS = 1;      

        /// <summary>
        /// The underlying Farseer Body that is used for this RigidBody.
        /// </summary>
        public Body Body { get { return mBody; } set { mBody = value; }  }
        
        /// <summary>
        /// Gets or sets the position of this RigidBody.
        /// </summary>
        public Vector2 Position { get { return mBody.Position; } set { mBody.Position = value; } }

        /// <summary>
        /// Gets or sets the rotation of this RigidBody.
        /// </summary>
        public Single Rotation { get { return mBody.Rotation; } set { mBody.Rotation = value; } }

        /// <summary>
        /// Gets or sets the velocity of this RigidBody.
        /// </summary>
        public Vector2 Velocity { get { return mBody.LinearVelocity; } set { mBody.LinearVelocity = value; } }

        /// <summary>
        /// Gets or sets the minimum velocity of this RigidBody.
        /// </summary>
        public Single MinimumVelocity { get { return mBody.MinimumVelocity; } set { mBody.MinimumVelocity = value; } }        

        /// <summary>
        /// Gets or sets the amount of angular velocity of this RigidBody.
        /// </summary>
        public Single AngularVelocity { get { return mBody.AngularVelocity; } set { mBody.AngularVelocity = value; } }

        /// <summary>
        /// Gets or sets the amount of drag of this RigidBody. 
        /// </summary>
        public Single Drag { get { return mBody.LinearDragCoefficient; } set { mBody.LinearDragCoefficient = value; } }

        /// <summary>
        /// Gets or sets the amount of angular drag of this RigidBody.
        /// </summary>
        public Single AngularDrag { get { return mBody.RotationalDragCoefficient; } set { mBody.RotationalDragCoefficient = value; } }

        /// <summary>
        /// Gets or sets the mass of this RigidBody.
        /// </summary>
        public Single Mass { get { return mBody.Mass; } set { mBody.Mass = value; } }

        /// <summary>
        /// Gets or sets whether this RigidBody should be affected by gravity or not.
        /// </summary>
        public Boolean IgnoreGravity { get { return mBody.IgnoreGravity; } set { mBody.IgnoreGravity = value; } }

        /// <summary>
        /// Gets or sets whether this RigidBody is static or not.
        /// </summary>
        public Boolean IsStatic { get { return mBody.IsStatic; } set { mBody.IsStatic = value; } }

        /// <summary>
        /// Gets or sets the moment of inertia of this RigidBody.
        /// </summary>
        public Single MomentOfInertia { get { return mBody.MomentOfInertia; } set { mBody.MomentOfInertia = value; } }

        /// <summary>
        /// Enable or disable this RigidBody.
        /// </summary>
        public new Boolean Enabled { get { return mBody.Enabled; } set { mBody.Enabled = value; } }

        /// <summary>
        /// Creates a new instance of a RigidBody component.
        /// </summary>
        /// <param name="gameObject">The GameObject that this component should be attached to.</param>
        public RigidBody(GameObject gameObject)
            : base(gameObject)
        {
            mBody = BodyFactory.Instance.CreateBody(1, 1);
        }

        /// <summary>
        /// Updates this RigidBody.
        /// </summary>
        public override void Update()
        {
            GameObject.Transform.Position = mBody.Position;
            GameObject.Transform.Rotation = mBody.Rotation;            
        }

        /// <summary>
        /// Applys a force to the RigidBody.
        /// </summary>
        /// <param name="amount">The amount of force to apply.</param>
        public void ApplyForce(Vector2 amount)
        {
            if(mBody != null)
                mBody.ApplyForce(amount);
        }

        /// <summary>
        /// Applies torque to the RigidBody.
        /// </summary>
        /// <param name="amount">The amount of torque to apply.</param>
        public void ApplyTorque(Single amount)
        {
            if (mBody != null)
                mBody.ApplyTorque(amount);
        }
    }
}
